package com.clp.protocol.core.event;

import com.clp.protocol.core.common.Container;
import com.clp.util.event.EventListener;
import com.clp.util.event.EventPublisher;
import org.jetbrains.annotations.Nullable;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.ExecutorService;

/**
 * 可监听容器
 * @param <E>
 */
public class ListenableContainer<E> extends Container<E> {
    private final EventPublisher<ListenableContainer<E>> eventPublisher;

    public ListenableContainer(ExecutorService executor) {
        this.eventPublisher = new EventPublisher<>(executor);
    }

    private void publishAddEvent(E element) {
        eventPublisher.publishEvent(new ListenableContainerEvent<>(this, ListenableContainerEvent.Type.ELEMENT_ADDED, element));
    }

    private void publishRemoveEvent(E element) {
        eventPublisher.publishEvent(new ListenableContainerEvent<>(this, ListenableContainerEvent.Type.ELEMENT_REMOVED, element));
    }

    public void addContainerEventListener(EventListener<ListenableContainerEvent<E>> listener) {
        eventPublisher.addEventListener(listener);
    }

    /**
     * 添加新的元素。
     *
     * @param m 要添加的新元素
     * @return 如果要添加的元素为null 或 元素已经存在，则添加失败；否侧，添加成功
     */
    @Override
    public boolean add(@Nullable E m) {
        boolean flag = super.add(m);
        if (flag) {
            publishAddEvent(m);
        }
        return flag;
    }

    @Override
    public boolean addAll(@Nullable Collection<? extends E> c) {
        boolean flag = super.addAll(c);
        if (flag) {
            c.forEach(this::publishAddEvent);
        }
        return flag;
    }

    /**
     * 移除元素
     * @param o 要移除的元素
     * @return 如果元素为null或不存在，则移除失败；否则，移除成功
     */
    @Override
    @SuppressWarnings("unchecked")
    public boolean remove(@Nullable Object o) {
        boolean flag = super.remove(o);
        if (flag) {
            publishRemoveEvent((E) o);
        }
        return flag;
    }

    @Override
    @SuppressWarnings("unchecked")
    public boolean removeAll(@Nullable Collection<?> c) {
        boolean flag = super.removeAll(c);
        if (flag) {
            c.forEach(e -> publishRemoveEvent((E) e));
        }
        return flag;
    }

    @Override
    public boolean retainAll(Collection<?> c) {
        return super.retainAll(c);
    }

    @Override
    public void clear() {
        List<E> list = new ArrayList<>(elements);
        super.clear();
        list.forEach(this::publishRemoveEvent);
    }

}
